# -*- coding:utf-8 -*-

import json
import os
from itertools import islice

import oss2
from aliyunsdkcore.client import AcsClient
from aliyunsdksts.request.v20150401 import AssumeRoleRequest
from django.conf import settings
from django.utils import timezone as tz

from social.account.models import User
from social.utils.hashid import encode_model_ids
from oss2.models import Tagging, TaggingRule


class OssFile:
    def __init__(self, bucket=settings.OSS_BUCKET_NAME, end_point=settings.OSS_ENDPOINT):
        self.auth = oss2.Auth(settings.OSS_ACCESS_KEY_ID, settings.OSS_ACCESS_KEY_SECRET)
        self.bucket = oss2.Bucket(self.auth, end_point, bucket)

    def set_meta(self, object_key, meta: dict):
        self.bucket.update_object_meta(object_key, meta)

    def get_meta(self, object_key):
        return self.bucket.head_object(object_key).headers

    def add_tag(self, object_key, key, value):
        rule = TaggingRule()
        rule.add(key, value)
        tagging = Tagging(rule)
        return self.bucket.put_object_tagging(object_key, tagging)

    def get_tags(self, object_key):
        return self.bucket.get_object_tagging(object_key).tag_set.tagging_rule

    def list_prefix(self, prefix, max_count=1000):
        if not prefix:
            raise ValueError("Needs prefix to list")
        return [x.key for x in list(islice(oss2.ObjectIterator(self.bucket, prefix), max_count))]


class OssSystem:
    def __init__(self, bucket_name=settings.OSS_BUCKET_NAME, end_point=settings.OSS_ENDPOINT):
        self.bucket_name = bucket_name
        self.end_point = end_point
        self.auth = oss2.Auth(settings.OSS_ACCESS_KEY_ID, settings.OSS_ACCESS_KEY_SECRET)

    @property
    def token_host(self):
        return "{0}.{1}".format(self.bucket_name, self.end_point)

    def get_token(self, user: User, callback_url=None, callback_body=None):
        now = tz.now()
        file_dir = ["image", "video", "sound"]

        user_id = encode_model_ids(User._meta.label, user.id, 0) if user.id else 'none'
        file_dir = {
            i + "_dir": os.path.join(i, "disucss", str(now.year), str(now.month), str(now.day),
                                     user_id)
            for i
            in file_dir}

        resource = [f"acs:oss:*:*:{self.bucket_name}/{i}/*" for i in file_dir.values()]
        print(resource)
        policy = json.dumps({
            "Version": "1",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Action": [
                        "oss:PutObject"
                    ],
                    "Resource": resource,
                    "Condition": {}
                }
            ]
        })

        client = AcsClient(settings.OSS_ACCESS_KEY_ID, settings.OSS_ACCESS_KEY_SECRET, settings.OSS_REGION_ID)
        request = AssumeRoleRequest.AssumeRoleRequest()
        request.set_RoleArn(settings.STS_ROLEARN)
        request.set_RoleSessionName(user.hid if user.id else user_id)
        #request.set_Policy(policy)

        request.set_accept_format('json')
        response = client.do_action_with_exception(request)
        result = json.loads(response.decode('utf8'))
        sts = result['Credentials']
        # sts.update(file_dir)
        sts['end_point'] = self.end_point
        sts['bucket'] = self.bucket_name
        if callback_url:
            _callbackBody = [
                "bucket=${bucket}",
                "raw_path=${object}",
                "size=${size}",
                "mime_type=${mimeType}",
                "height=${imageInfo.height}",
                "width=${imageInfo.width}",
                "format=${imageInfo.format}",
                "etag=${etag}"
            ]
            if callback_body:
                for key, value in callback_body.items():
                    _callbackBody.append("{}={}".format(key, value))
            sts['callback'] = {
                "url": callback_url,
                "body": '&'.join(_callbackBody),
            }
        return sts

    def upload(self, file_location, filename):
        # filename 应携带dir部分
        result = self.bucket.put_object_from_file(filename, file_location)
        return result

    @property
    def bucket(self):
        return oss2.Bucket(self.auth, self.end_point, self.bucket_name, connect_timeout=30)

# class OssSystem(object):
#     def __init__(self, bucket_name, end_point=env.OSS_ENDPOINT, access_key_id=env.OSS_ACCESS_KEY_ID,
#                  access_key_secret=env.OSS_ACCESS_KEY_SECRET):
#         self.access_key_id = access_key_id
#         self.access_key_secret = access_key_secret
#         self.bucket_name = bucket_name
#         self.end_point = end_point
#         self.auth = oss2.Auth(self.access_key_id, self.access_key_secret)
#
#     def upload(self, file_location, filename):
#         # filename 应携带dir部分
#         result = self.bucket.put_object_from_file(filename, file_location)
#         return result
#
#     @property
#     def bucket(self):
#         return oss2.Bucket(self.auth, self.end_point, self.bucket_name, connect_timeout=30)
#
#     @property
#     def token_host(self):
#         return "http://{0}.{1}".format(self.bucket_name, self.end_point)
#
#     def __get_iso_8601(self, expire_time_second):
#         now = int(time.time())
#         expire_sync_point = now + expire_time_second
#         gmt = datetime.datetime.fromtimestamp(expire_sync_point).isoformat()
#         gmt += 'Z'
#         return gmt, now + expire_time_second
#
#     def get_token(self, user, upload_dir=None, callback_url=None, callbackBody=None, expire_time_second=60 * 60):
#         if upload_dir:
#             condition_array = [["starts-with", "$key", upload_dir]]
#         else:
#             condition_array = []
#         expire, expire_sync_point = self.__get_iso_8601(expire_time_second)
#         policy_dict = {"expiration": expire, "conditions": condition_array}
#         policy = json.dumps(policy_dict).strip().encode("utf8")
#         policy = base64.b64encode(policy)
#         if callback_url:
#             _callbackBody = [
#                 "bucket=${bucket}",
#                 "filename=${object}",
#                 "filesize=${size}",
#                 "mimeType=${mimeType}",
#                 "height=${imageInfo.height}",
#                 "width=${imageInfo.width}",
#                 "format=${imageInfo.format}",
#                 "hash=${etag}"
#             ]
#             if callbackBody:
#                 for key, value in callbackBody.items():
#                     _callbackBody.append("{}={}".format(key, value))
#             _callbackBody = '&'.join(_callbackBody)
#             callback_dict = {
#                 "callbackUrl": callback_url,
#                 "callbackBody": _callbackBody,
#                 "callbackBodyType": "application/x-www-form-urlencoded",
#             }
#             callback_param = json.dumps(callback_dict).strip().encode("utf8")
#             base64_callback_body = base64.b64encode(callback_param).decode()
#         else:
#             base64_callback_body = None
#         access_key_secret = self.access_key_secret.encode("utf8")
#         h = hmac.new(access_key_secret, policy, sha1)
#         sign_result = base64.encodebytes(h.digest()).strip().decode()
#         token_dict = {
#             "accessid": self.access_key_id,
#             "host": self.token_host,
#             "policy": policy.decode(),
#             "signature": sign_result,
#             "expire": expire_sync_point,
#             "callback": base64_callback_body,
#         }
#         now = tz.now()
#         for i in ["image", "video", "sound"]:
#             token_dict[i + "_dir"] = os.path.join(i, str(now.year), str(now.month), str(now.day),
#                                                   encode_model_ids(User._meta.app_label, user.id))
#         return token_dict
